using System;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

namespace Slaks.Web.Parser.Utils
{
	/// <summary>
	/// Get the web page from the web site
	/// </summary>
	public class WebPageDownload
	{
		protected readonly static string m_contentTypePattern = @"charset\s*=\s*(?<charset>.+)";
		protected readonly static string m_contentTypePatternSecondChance = @"charset\s*=\s*(?<charset>.+)[""']";
		protected static int m_timeOut = 10000;

		public static string GetWebPage(string filepage,ref Encoding encoding)
		{
			return GetWebPage(filepage, ref encoding, m_timeOut);
		}

		public static string GetWebPage(string filepage,ref Encoding encoding, int timeout)
		{
			HttpWebResponse response = null;
			Stream stream = null;
			StreamReader reader = null;
			string buffer = String.Empty;
			string encodingName;

			try
			{
				HttpWebRequest request = (HttpWebRequest) WebRequest.Create(new Uri(filepage));
				request.Timeout = timeout;
				request.UserAgent =  "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)";
				response = (HttpWebResponse) request.GetResponse();
				if (response == null) throw new WebException("Request timed out for " + filepage);
				stream = response.GetResponseStream();
				if (!response.ContentType.ToLower().StartsWith("text/")) return null;

				Match m = Regex.Match(response.ContentType, m_contentTypePattern, RegexOptions.IgnoreCase);
				if (m.Success)
				{
					encodingName = m.Groups["charset"].Value;
					Encoding enc = Encoding.GetEncoding(encodingName);
					if (enc != null) encoding = enc;
				}
				if (!m.Success) 
				{
					reader = new StreamReader(stream, encoding, true);
					if (reader == null) throw new Exception("Stream Reader is null for " + filepage);

					buffer = reader.ReadToEnd();
					encodingName = WebPageDownload.EstimateEncodingSecondChance(buffer);
					if (encodingName.Length > 0)
					{
						Encoding newEncoding = null;
						bool isEncodingCorrect = true;
						try
						{
							newEncoding = Encoding.GetEncoding(encodingName);
						}
						catch(Exception){ isEncodingCorrect = false;}

						if (isEncodingCorrect) 
						{
							//read stream with new encoding
							if (encoding != newEncoding)
							{
								response.Close();
								reader.Close();
								stream.Close();

								request = (HttpWebRequest) WebRequest.Create(new Uri(filepage));
								request.Timeout = timeout;
								response = (HttpWebResponse) request.GetResponse();
								if (response == null) throw new WebException("Request timed out for " + filepage);
								stream = response.GetResponseStream();
								if (!response.ContentType.ToLower().StartsWith("text/")) return null;

								reader = new StreamReader(stream, newEncoding, true);
								if (reader == null) throw new Exception("Stream Reader is null for " + filepage);
								buffer = reader.ReadToEnd();

								encoding = newEncoding;
							}
						}
						
					}
				}
				else
				{
					reader = new StreamReader(stream, encoding, true);
					if (reader == null) throw new Exception("Stream Reader is null for " + filepage);
					buffer = reader.ReadToEnd();
				}

				return buffer;
			}
			catch (Exception e)
			{
				throw e;
			}
			finally
			{
				if (reader != null)
					reader.Close();

				if (stream != null)
					stream.Close();

				if (response != null)
					response.Close();
			}
		} //end of function

		/// <summary>
		/// Try to detect the encoding from the html tags
		/// </summary>
		/// <remarks>
		/// If the encoding can not be assessed from WebResponse, then download the html file and try to detect the encoding out of it.
		/// </remarks>
		/// <param name="buffer"></param>
		/// <returns></returns>
		internal static string EstimateEncodingSecondChance(string buffer)
		{
			string encoding = String.Empty;
			Match m = Regex.Match(buffer, m_contentTypePatternSecondChance, RegexOptions.IgnoreCase|RegexOptions.Multiline);
			if (m.Success)
			{
				encoding = m.Groups["charset"].Value;
			}

			return encoding;
		}

		/// <summary>
		/// Set or Get time out delay for page request
		/// </summary>
		public static int TimeOut
		{
			get { return m_timeOut; }
			set { m_timeOut = value; }
		}

	}
}